#include <crt_sem.h>


#if (TARGET_OS == OS_WINDOWS)

int	 _sem_init(_sem_t* sem, unsigned int value) {

	*sem = CreateSemaphore(NULL, value, INT_MAX, NULL);

	if (*sem == NULL)
		return -1;
	else
		return 0;
	return 0;
}

void _sem_destroy(_sem_t* sem) {

	if(*sem != INVALID_HANDLE_VALUE)
		CloseHandle(*sem);
}

void _sem_post(_sem_t* sem) {

	if (ReleaseSemaphore(*sem, 1, NULL) == 0)
	{
		abort();
	}
}

void _sem_wait(_sem_t* sem) {

	DWORD dw = WaitForSingleObject(*sem, INFINITE);

	if (dw == WAIT_OBJECT_0)
		return;

	if (dw == WAIT_TIMEOUT)
		return;
}

int	_sem_trywait(_sem_t* sem) {

	DWORD r = WaitForSingleObject(*sem, 0);

	if (r == WAIT_OBJECT_0)
		return S_SUCCESS;

	if (r == WAIT_TIMEOUT)
		return S_ERROR;

	return S_ERROR; 
}

int	_sem_wait_time(_sem_t* sem, unsigned int sec)
{
	DWORD r = WaitForSingleObject(*sem, sec * 1000);

	if (r == WAIT_OBJECT_0)
		return S_SUCCESS;

	if (r == WAIT_TIMEOUT)
		return S_ERROR;

	return S_ERROR;
}

#elif (TARGET_OS == OS_POSIX)

int	 _sem_init(_sem_t* sem, unsigned int value) {

	if (sem_init(sem, 0, value))
		return S_ERROR;
	return S_SUCCESS;
}

void _sem_destroy(_sem_t* sem) {

	if (sem_destroy(sem))
		abort();
}

void _sem_post(_sem_t* sem) {

	if (sem_post(sem))
		abort();
}

void _sem_wait(_sem_t* sem) {

	int r = 0;

	r = sem_wait(sem);

	if (r == 0) {
		
	} else if (r == -1 && errno == EINTR) {
		abort();
	}
}

 int _sem_trywait(_sem_t* sem) {

	int r = 0;

	r = sem_trywait(sem);

	if (r == 0) {
		
	}
	else if (r == -1 && errno == EINTR) {
		abort();
		return S_ERROR;
	}
	return S_SUCCESS;
}
int _sem_wait_time(_sem_t* sem, unsigned int sec)
{
	return S_ERROR;
 }


#elif(TARGET_OS == OS_DARWIN)

int _sem_init(_sem_t* sem, unsigned int value) {

    kern_return_t err;
    err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
    if (err == KERN_SUCCESS)
        return S_SUCCESS;
    abort();
    return S_ERROR;  /* Satisfy the compiler. */
}

void _sem_destroy(_sem_t* sem) {
	
    if (semaphore_destroy(mach_task_self(), *sem))
        abort();
}

void _sem_post(_sem_t* sem) {

    if (semaphore_signal(*sem))
       abort();
}

void _sem_wait(_sem_t* sem) {
	
    int r;

    do{
        r = semaphore_wait(*sem);
    } while (r == KERN_ABORTED);

    if (r != KERN_SUCCESS)
        abort();
}

int	_sem_trywait(_sem_t* sem) {

    
    mach_timespec_t interval;
    kern_return_t err;

    interval.tv_sec = 0;
    interval.tv_nsec = 0;

    err = semaphore_timedwait(*sem, interval);
    if (err == KERN_SUCCESS)
        return S_SUCCESS;
    
	return S_ERROR;
}


int _sem_wait_time(_sem_t* sem, unsigned int sec)
{
	return S_SUCCESS;
}



#endif

